/**********************************************************************************************************************
 *
 * Project:    mGameEngine
 * File:       sky.h
 * Author:     karooolek
 * Created on: Jan 4, 2010
 *
 **********************************************************************************************************************/

#ifndef SKY_H_
#define SKY_H_

#include "scenenode.h"
#include "clouds.h"

namespace mGameEngine
{
namespace Game
{

/**
 * Sky.
 * Sky uses sky gradient texture.
 * One side of the sky (far side) can be specified darker due to
 * light absorbption.
 * There is the sun with specified color, lightness factor
 * and position. It's position can be calculated 
 * for specified earth coordinates (longitude and lattitude)
 * and time of year and day.
 * Multiple clouds layers can be attached to sky.
 * Environment map can be generated.
 */
class Sky: public SceneNode, public Graphics::Drawable
{
protected:
    /**
     * Clouds.
     */
    List<Clouds *> _clouds;

    /**
     * Sky gradient.
     */
    const Graphics::Texture *_skyGradient;

    /**
     * Far sky darkness.
     */ 
    float _darkness;

    /**
     * Sun light.
     */
    Graphics::DirectionalLight _sun;

    /**
     * Sun lightness.
     */
    float _lightness;

    /**
     * Sun angular size.
     */
    float _sunSize;

    /**
     * Generated environment map.
     */
    mutable Graphics::RenderTexture _environmentMap;

public:
    /**
     * Create sky.
     */
    Sky();

    /**
     * Destroy sky.
     */
    virtual ~Sky();

    /**
     * Get sky gradient.
     * @return sky gradient.
     */
    const Graphics::Texture *getSkyGradient() const
    {
        return _skyGradient;
    }

    /**
     * Set sky gradient.
     * @param skyGradient sky gradient.
     */
    void setSkyGradient(const Graphics::Texture *skyGradient)
    {
        _skyGradient = skyGradient;
    }

    /**
     * Get far sky darkness.
     * @return far sky darkness.
     */
    float getSkyDarkness() const
    {
        return _darkness;
    }

    /**
     * Set far sky darkness.
     * @param darkness far sky darkness.
     */
    void setSkyDarkness(float darkness)
    {
        if(darkness < 0.0f)
        {
            return;
        }

        _darkness = darkness;
    }

    /**
     * Get sun color.
     * @return sun color.
     */
    const Color &getSunColor() const
    {
        return _sun.getDiffuseColor();
    }

    /**
     * Set sun color.
     * @param sunColor sun color.
     */
    void setSunColor(const Color &sunColor);

    /**
     * Get sun lightness.
     * @return sun lightness.
     */
    float getSunLightness() const
    {
        return _lightness;
    }

    /**
     * Set sun lightness.
     * @param higlight sun lightness.
     */
    void setSunLightness(float lightness)
    {
        if(lightness < 0.0f)
        {
            return;
        }

        _lightness = lightness;
    }

    /**
     * Get sun direction.
     * @return sun position.
     */
    const Vector3 &getSunDirection() const
    {
        return _sun.getDirection();
    }

    /**
     * Set sun direction.
     * @param dir sun direction.
     */
    void setSunDirection(const Vector3 &dir);

    /**
     * Set sun direction calculated for given earth coordinates
     * and date and time.
     * @param coords earth coordinates, longitude and lattitude in deegrees.
     * @param day day of a year: 0 - January 1st, 365 - December 31st.
     * @param hour hour of the day: 0/24 - midnight, 12 - noon.
     */
    void setSunDirection(const Vector2 &coords, float day, float hour);

    /**
     * Get sun angular size.
     * @return sun angular size (in radians).
     */
    float getSunSize() const
    {
        return _sunSize;
    }

    /**
     * Set sun angular size.
     * @param sunSize sun angular size (in radians).
     */
    void setSunSize(float sunSize)
    {
        if(sunSize < 0.0)
        {
            return;
        }

        _sunSize = sunSize;
    }

    /**
     * Get clouds layers.
     * @return clouds layers.
     */
    const List<Clouds *> &getClouds() const
    {
        return _clouds;
    }

    /**
     * Add new clouds layer.
     * @param clouds clouds layer.
     */
    void addClouds(Clouds *clouds);

    /**
     * Remove clouds layer.
     * @param clouds clouds layer.
     */
    void removeClouds(Clouds *clouds);

    /**
     * Regenerate environment map.
     */
    void generateEnvironmentMap() const;

    /**
     * Get environment map.
     * @return environment map with recently generated sky.
     */
    const Graphics::Texture *getEnvironmentMap() const
    {
        return &_environmentMap;
    }

    /**
     * Draw sky.
     */
    virtual void draw() const;
};

}
}

#endif // SKY_H_
